import { APlugin } from '../types/common.interface';
import { TableDatas } from '../cors/table-datas';
import { Inject, Injectable, PluginInjectable } from '../decorators/inject';
import { Hook } from '../cors/hook';
import { NExcel } from '../types';
import { Config } from '../cors/config';
import { filter } from 'rxjs/operators';
import './row-height.plugin.less';
import { RenderTrigger } from '../cors/render-trigger';
import { Cache } from '../cors/cache';
import { TableEvent } from '../cors/table-event';
import './scroll-y.less';

@Injectable()
@PluginInjectable('ScrollY')
export class ScrollY  extends APlugin{
    protected scrollContainer!: HTMLElement;
    protected scrollInnerEle!: HTMLElement;
    protected scrollSpace: number = 5;
    constructor(
        @Inject(NExcel.OperateContainerToken) protected ele: HTMLElement,
        protected conf: Config,
        protected tableData: TableDatas,
        protected cache: Cache,
        protected renderTrigger: RenderTrigger,
        protected tableEvent: TableEvent,
        protected hook: Hook
    ) {
        super()
    }
    public init() {
        this.initDom();
        this.bindDomEvent();
    }
    protected initDom() {
        this.scrollContainer = document.createElement('div');
        this.scrollContainer.setAttribute('class', 'z-excel-scroll-y');
        this.scrollInnerEle = document.createElement('div');
        this.scrollContainer.append(this.scrollInnerEle);
        let maxRow = this.conf.defaultMaxScroll.row + 1;
        let defaultRowHeight = this.conf.header.row.height;
        this.scrollInnerEle.setAttribute('class', 'z-excel-scroll-inner');
        this.scrollInnerEle.setAttribute('style', `height: ${maxRow * defaultRowHeight / this.conf.enlarge}px;`)
        this.ele.append(this.scrollContainer);
        this.hook.pixelRatioChange.add(() => {
            this.scrollSpace = this.conf.header.row.height / this.conf.enlarge / 4;
        });
        this.hook.afterScaleChange.add(() => {
            this.scrollSpace = this.conf.header.row.height / this.conf.enlarge / 4;
        })
        this.hook.tableDataChange.add(() => {
            this.listenChange();
        });
        this.hook.afterDeleteRow.add(() => {
            this.listenChange();
        });
        this.hook.afterDeleteCol.add(() => {
            this.listenChange();
        });
        this.hook.afterInsertRow.add(() => {
            this.listenChange();
        });
        this.hook.afterInsertCol.add(() => {
            this.listenChange();
        });
        this.hook.afterRowHeightChange.add(() => {
            this.listenChange();
        });
        this.hook.afterColWidthChange.add(() => {
            this.listenChange();
        });
        this.hook.pixelRatioChange.add(() => {
            this.listenChange();
        });
        this.hook.afterScaleChange.add(() => {
            this.listenChange();
        });
    }
    protected timmer: any= null;
    protected listenChange() {
        if(this.timmer !== null) {
            clearTimeout(this.timmer);
        }
        this.timmer = setTimeout(() => {
            let maxRow = Math.max(this.conf.defaultMaxScroll.row + 1, this.tableData.rows.length);
            let totalHeight = 0;
            for(let i = 0; i < maxRow; i++) {
                totalHeight += this.tableData.getRowHeight(i);
            }
            let scrollTop = this.scrollContainer.scrollTop;
            // if(scrollTop === 0) return;
            let innerHeight = Number(this.scrollInnerEle.style.height.replace('px', ''));
            let newHeight = totalHeight / this.conf.enlarge;
            this.scrollInnerEle.setAttribute('style', `height: ${newHeight}px;`);
            this.scrollContainer.scrollTop = (scrollTop / innerHeight) * newHeight;
            let newEvt = new Event('scroll');
            this.scrollContainer.dispatchEvent(newEvt);
            this.timmer = null
        }, 100);
    }
    protected bindDomEvent() {
        this.scrollContainer.addEventListener('scroll', (evt) => {
            let scrollTop = this.scrollContainer.scrollTop * this.conf.enlarge;
            this.conf.view.row = scrollTop;
            this.renderTrigger.triggerRenderAll();
        });
        this.tableEvent.scrollObs$.pipe(filter((event) => {
            if(event.directive === 'bottom' || event.directive === 'top') {
                return true;
            }
            if(this.scrollInnerEle.clientHeight <= this.scrollContainer.clientHeight) {
                return false;
            }
            return false;
        })).subscribe((event: any) => {
            if(event.directive === 'bottom') {
                this.scrollContainer.scrollTop = this.scrollContainer.scrollTop + this.scrollSpace;
            } else {
                this.scrollContainer.scrollTop = this.scrollContainer.scrollTop - this.scrollSpace;
            }
            let newEvt = new Event('scroll',event.event);
            this.scrollContainer.dispatchEvent(newEvt)
        });
    }
    public destroy(): void {
        
    }
}